"""
数据模型
"""

from pydantic import BaseModel

import utils.enum_utils as enum
from my_typing import *
from utils.data_utils.special import ObjectIdStr
from utils.mock_utils import (
    DATETIME,
    Demo,
)
from utils.validator_utils.pydantic_validator.field import (
    CharField,
    IntegerField,
    ListField,
    NormalField,
    QueryIntegerField,
)


class AnyTypeBase(BaseModel):
    """ 模型 | 基类（允许接收非 Python 标准类型的数据） """

    class Config:
        arbitrary_types_allowed: bool = True
        """ 允许接收非 Python 标准类型的数据 """


# ============================== VO、PO 基类 ==============================

class VOBase(BaseModel, extra="ignore"):
    """ VO | 基类 """


TVO = TypeVar("TVO", bound=VOBase, covariant=True)
""" 继承 VOBase 的类（支持协变） """


class POBase(AnyTypeBase):
    """ PO | 基类 """

    create_time: datetime = NormalField(default_factory=DATETIME.now, title="创建时间")
    id: ObjectIdStr = NormalField(default_factory=ObjectIdStr, title="主键（ObjectId 字符串）")
    is_deleted: bool = NormalField(False, title="是否已删除")
    update_time: datetime = NormalField(default_factory=DATETIME.now, title="更新时间")

    @staticmethod
    def base_fields() -> SetStr:
        """ 基础字段 """

        return {
            "create_time",
            "id",
            "is_deleted",
            "update_time",
        }

    def to_db_dict(self) -> dict:
        """ 转换成入库的字典（id 赋值给 _id） """

        return {
            "_id": self.id.oid,
            **self.model_dump(),
        }

    def update_from_request(self, request: "TRequest") -> None:
        """ 从请求中更新数据（仅适用于字段及类型相同的情况） """

        for field, value in request.model_dump().items():
            if field in self.model_fields_set:
                setattr(self, field, value)


TPO = TypeVar("TPO", bound=POBase, covariant=True)
""" 继承 POBase 的类（支持协变） """


# ============================== 通用字段 基类 ==============================

class QueryFieldBase:
    """ 查询字段 | 基类 """

    page: int = QueryIntegerField(1, title="页码", min_value=1)
    page_size: int = QueryIntegerField(10, title="每页数据条数", min_value=1, max_value=100)


class ListFieldBase:
    """ 列表字段 | 基类 """

    data_list: list = ListField(..., title="分页后的数据")


# ============================== 查询 基类 ==============================

class Page(BaseModel):
    """ 分页 | Model """

    data_count: int = IntegerField(..., title="总数据条数", min_value=0)
    data_list: Iterable = ListField(..., title="分页后的数据")
    page: int = IntegerField(1, title="页码", min_value=1)
    page_count: int = IntegerField(..., title="总页数", min_value=0)
    page_size: int = IntegerField(10, title="每页数据条数", min_value=1)


class POPage(Page, Generic[TPO]):
    """ PO 分页 | Model """

    data_list: Iterable[TPO] = ListField(..., title="分页后的 PO 数据")


TPOPage = TypeVar("TPOPage", bound=POPage, covariant=True)
""" 继承 POPage 的类（支持协变） """


class VOPage(BaseModel, Generic[TVO]):
    """ PO 分页 | Model """

    data_list: list[TVO] = ListField(..., title="分页后的 VO 数据")


TVOPage = TypeVar("TVOPage", bound=VOPage, covariant=True)
""" 继承 VOPage 的类（支持协变） """


class PageSorting(BaseModel):
    """
    分页排序参数 | Model

        - field (str): 排序字段
        - order (enum.MongoSorting): 排序方式
    """

    field: str = CharField(..., title="排序字段", min_length=1)
    order: enum.MongoSorting = IntegerField(..., title="排序方式")

    @staticmethod
    def get_sorting_by_map(mapping: dict[str, enum.MongoSortOrNone]) -> DictStrInt:
        """ 根据映射获取排序字典 """

        return {
            model_field: int(order)
            for model_field, order in mapping.items()
            if order is not None
        }


class PageQuery(BaseModel):
    """ 分页查询参数 | Model """

    page: int = IntegerField(1, title="页码", min_value=1)
    page_size: int = IntegerField(10, title="每页数据条数", min_value=1, max=100)
    query: dict = NormalField(default_factory=dict, title="自定义查询参数")
    sorting: DictStrInt = NormalField(default_factory=dict, title="排序字典", examples=[{"create_time": 1}])


# ============================== 请求体、响应体 基类 ==============================

class RequestBase(AnyTypeBase):
    """ Request VO | 基类 """


TRequest = TypeVar("TRequest", bound=RequestBase, covariant=True)
""" 继承 RequestBase 的类（支持协变） """


class ListRequestBase(RequestBase):
    """ 列表 | Request VO | 基类 """

    # -------------------- 分页字段 --------------------
    page: int = QueryFieldBase.page
    page_size: int = QueryFieldBase.page_size

    # -------------------- 排序字段 --------------------
    # sort_by_create_time: enum.MongoSortOrNone = XXXSortField.sort_by_create_time

    # -------------------- 查询字段 --------------------
    # name: StrOrNone = XXXQueryField.name

    # -------------------- 列表 from_query 方法 --------------------
    # @classmethod
    # def from_query(
    #     cls,
    # ) -> "ListRequestBase":
    #     return cls(
    #     )

    def get_sorting_dict(self) -> DictStrInt:
        """ 获取排序字典 """

        sorting_dict: DictStrInt = {}

        for field, sorting in self.model_dump(exclude_none=True).items():
            if not field.startswith("sort_by_"):
                continue

            db_field: str = field.removeprefix("sort_by_")
            sorting_dict[db_field] = int(sorting)

        return sorting_dict


class ResponseBase(BaseModel):
    """ Response VO | 基类 """

    code: enum.HTTPStatusCode = IntegerField(
        enum.HTTPStatusCode.HTTP_200_OK,
        title="响应状态码",
        min_value=enum.HTTPStatusCode.HTTP_100_CONTINUE,
        max_value=enum.HTTPStatusCode.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED,
    )
    data: dict = NormalField(default_factory=dict, title="响应数据")
    errors: ListStr = ListField(default_factory=list, title="错误提示")
    message: enum.HTTPStatusCode.label_type = CharField(enum.HTTPStatusCode.HTTP_200_OK.label_en, title="响应消息")


class OK(ResponseBase):
    """ 成功响应 | Model """


class OKWithData(ResponseBase, Generic[TVO]):
    """ 成功响应（携带数据） | Model """

    data: TVO = NormalField(..., title="响应数据")


class OKWithPage(ResponseBase, Generic[TVOPage]):
    """ 成功响应（携带分页数据） | Model """

    data: TVOPage = NormalField(..., title="分页数据")


# # ============================== 泛型 类型提示 ==============================
#
# TPage = TypeVar("TPage", bound=Page, covariant=True)
# """ 继承 Page 的类（支持协变） """
#
# TRequest = TypeVar("TRequest", bound=RequestBase, covariant=True)
# """ 继承 RequestBase 的类（支持协变） """
#
# TPO = TypeVar("TPO", bound=POBase, covariant=True)
# """ 继承 POBase 的类（支持协变） """
#
# TVO = TypeVar("TVO", bound=VOBase, covariant=True)
# """ 继承 VOBase 的类（支持协变） """

# ============================== 测试代码 ==============================

if __name__ == "__main__":
    from devtools import debug

    p1 = POBase()
    # p1 = POBase(id=ObjectIdStr())
    debug(p1.__dict__)
    debug(p1.to_db_dict())
